package serveur;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.sql.SQLException;
import java.util.ArrayList;

import client.Client;

/**
 * Classe ThreadClient
 *
 */
public class ThreadClient implements Runnable
{
      private Thread _t; // contiendra le thread du client
	  private Socket _s; // recevra le socket liant au client
	  private PrintWriter out; // pour gestion du flux de sortie
	  private BufferedReader in; // pour gestion du flux d'entrée
	  private serveur.Serveur serveur; // pour utilisation des méthodes de la classe principale
	  private Client client;
	  String existe;
	  ArrayList<Client> listeAmis=new ArrayList<Client>();
	  private String email;
	  private String var;
	  private int existe2;
	  private String demandeur;
	  private int conn=0;
	  private String message;
	  private String motDePasse;
      private char charCur[] = new char[1];
	private int rep;
	private int rep2; 
	  
	  
	  /** Constructeur : crée les éléments nécessaires au dialogue avec le client **/
	  // le param s est donné dans Serv par ss.accept()
	  public ThreadClient(Socket s, Serveur serv) 
	  {
		// passage de local en global (pour gestion dans les autres méthodes)
	    serveur=serv; 
	    _s=s;
	    try
	    {
	    	// fabrication d'une variable permettant l'utilisation du flux de sortie avec des string
	    	out = new PrintWriter(_s.getOutputStream());
	    	// fabrication d'une variable permettant l'utilisation du flux d'entrée avec des string
	    	in = new BufferedReader(new InputStreamReader(_s.getInputStream()));
	    }
	    catch (IOException e){ }
	    _t = new Thread(this); // instanciation du thread
	    _t.start(); // demarrage du thread, la fonction run() est ici lancée
	  }//fin ThreadClient()

	  
	  /** Methode :  exécutée au lancement du thread par t.start() **/
	  // Elle attend les messages en provenance du serveur et les redirige 
	  public void run()
	  {
		  // on indique dans la console la connection d'un nouveau client
		  try
		  {
	      // la lecture des données entrantes se fait caractère par caractère ...
	      // ... jusqu'à trouver un caractère de fin de chaine
	      // déclaration d'un tableau de char d'1 élement, _in.read() y stockera le char lu

	   // attente en boucle des messages provenant du client (bloquant sur _in.read())
	      while (true)
	      {
	    	  if(in.read(charCur, 0, 1)!=-1)
	    	  {
	    		  if(charCur[0]=='C'){
	    			  connexion();
	    		  }

	    		  if(charCur[0]=='I'){
	    			  inscription();
	    		  }
	    		  if(charCur[0]=='D'){
	    			  demandeAmi();
	    		  }
	    		  if(charCur[0]=='V'){
	    			  verifDemande();
	    		  }
	    		  if(charCur[0]=='M'){
	    			  envoieMess();
	    		  }
	    		  if(charCur[0]=='R'){
	    			  afficheDemande();
	    		  }
	    		  if(charCur[0]=='O'){
	    			  demandeAcceptee();
	    		  }
	    		  if(charCur[0]=='S'){
	    			  supprimeDemande();
	    		  }
	    		  if(charCur[0]=='Z'){
	    			  deconnexionClient();
	    		  }
	    		  if(charCur[0]=='T'){
	    			  actualisationStatut();
	    		  }
	    		  if(charCur[0]=='P'){
	    			  actualisationPseudo();
	    		  }
	    		  if(charCur[0]=='F'){
	    			  envoieMessHL();
	    		  }	  
	    		  if(charCur[0]=='G'){
	    			  supprimeMess();
	    		  }	
	    	  }	
      		}//fin while(true)
		  }	
		  catch (Exception e){ }	    
		}//fin run()
	  
	  /** Methode connexion() **/
	  public void connexion() throws IOException, SQLException
	  {
    	  email=""; motDePasse="";
    	  boolean mDp=false;
    	  in.read(charCur, 0, 1);
    	  while(charCur[0]!=-1) 
    	  {
	      	// on regarde si on arrive à la fin d'une chaine ...
	    	  if (charCur[0] != '\u0000' )
	    	  {
	    		  if(charCur[0]!=';' && mDp==false)
	              	email += charCur[0]; // ... si non, on concatène le caractère dans le message
	    		  else
	    		  {
	        		mDp=true;
	        		if(charCur[0]!=';')
	        			motDePasse +=charCur[0];
	    		  }//fin else
	    		  in.read(charCur, 0, 1);
	    	  }//fin if
	    	  else if(!email.equalsIgnoreCase("")&& !motDePasse.equalsIgnoreCase("")) // juste une vérification de principe
	    	  {
		          conn=serveur.verifConnection(email, motDePasse);
		        //on ajoute le client dans la liste des connectés et on lui met le statut en ligne
		    	  client= new Client(out, email, null, null, null,"En ligne","Aucun pseudo");
		    	  serveur.addClient(client);
			       //on envoie la liste des messages du client
		          ArrayList<String> messages=serveur.recupereListeMessages(email);
		          out.write("E");
		          for(int i=0;i<messages.size();i++){
		        	  out.write(messages.get(i));
		        	  out.write(";");
		          }
		          out.write("\u0000");
		          out.flush();
		          //on récupère la liste des amis déjà connectés à la messagerie(email,pseudo et statut)
		          listeAmis=serveur.listeAmisClientsC(email,true);
		          int i=0;
		          out.write("C"+conn);
		          while(listeAmis.size()!=i)
		          {
		        	  out.write(listeAmis.get(i).getEmail()+","+listeAmis.get(i).getStatut()+","+
		        			  listeAmis.get(i).getPseudo()+";");
		        	  i++;
		          }
		          out.write("\n");
		          i=0;
		          listeAmis=serveur.listeAmisClientsC(email, false);
		          while(listeAmis.size()!=i)
		          {
		        	  out.write(listeAmis.get(i).getEmail()+",");
		        	  i++;
		          }
		          //Si il n'y a pas de clients connectés
		          if(i==0) out.write("0");
		          out.write("\u0000");out.flush();
		    	  //on affiche la liste des clients connectés
		    	  serveur.afficheClients();	
		    	  //on envoie le nouvel ami connecté 
		    	  serveur.ActualiseListeAmis(client.getEmail(),true);
		          
		    	  break;
	    	  	}//fin else
      		}//fin while  
	  }//fin connexion()
	  
	/** Methode inscription() **/  
	public void inscription() throws IOException
	{
			email=""; motDePasse="";
			String nom=""; String prenom="";
			boolean mail=false;boolean mDp=false;boolean nm=false;
			in.read(charCur, 0, 1);
			while(charCur[0]!=-1) 
			{
				if (charCur[0] != '\u0000' && charCur[0] != '\n' && charCur[0] != '\r'){
					//on recupere les donnees
					if (charCur[0]!=';')//si c'est un caractere
					{
						if(mail==false){email+=charCur[0];}
						else if(mDp==false){motDePasse+=charCur[0];}
						else if(nm==false){nom+=charCur[0];}
						else {prenom+=charCur[0];}
					}
					else //si c'est un ';'
					{
						if(mail==false){mail=true;}
						else if(mDp==false){mDp=true;}
						else {nm=true;}			      						
					}
					in.read(charCur, 0, 1);
				}
				else 
					if(!email.equalsIgnoreCase("")&& !motDePasse.equalsIgnoreCase("") && !nom.equalsIgnoreCase("") && !prenom.equalsIgnoreCase("")) // juste une vérification de principe
				{
					client= new Client(out, email,nom,prenom,motDePasse,"En ligne","");
					rep = serveur.verifEmailExistePas(client);
					rep2 = serveur.inscrireClient(client);
					out.write("I"+rep+rep2); out.flush();	  
					break;
				}				
			}//fin while
	} //fin inscription()
	      		
	/** Methode demandeAmi()**/
	public void demandeAmi() throws IOException
	{
      		email=""; String demande="";
	    	boolean dem=false;
	    	in.read(charCur, 0, 1);
	    	while(charCur[0]!=-1) {
		      	// on regarde si on arrive à la fin d'une chaine ...
		        if (charCur[0] != '\u0000' && charCur[0] != '\n' && charCur[0] != '\r'){
		        	if(charCur[0]!=';' && dem==false)
		                email += charCur[0]; // ... si non, on concatène le caractère dans le message
		        	else{
		        			dem=true;
		        			if(charCur[0]!=';')
		        				demande +=charCur[0];
		        	}
			        in.read(charCur, 0, 1);
		        }
		        else if(!email.equalsIgnoreCase("")&& !demande.equalsIgnoreCase("")) // juste une vérification de principe
		        {
			      existe=serveur.verifAdrExiste(email,demande);
			      int exist;int dejaAmi;int pasEncoreDem;
		          if (existe.compareTo("110")==0 || existe.compareTo("100")==0 || existe.compareTo("111")==0 || existe.compareTo("101")==0 )exist=1;
		          else exist=0;			         
		          if (existe.compareTo("110")==0 || existe.compareTo("010")==0 || existe.compareTo("111")==0 || existe.compareTo("011")==0)dejaAmi=1; 
		          else dejaAmi=0;
		          if (existe.compareTo("001")==0 || existe.compareTo("101")==0 || existe.compareTo("111")==0 || existe.compareTo("011")==0)pasEncoreDem=1; 
		          else pasEncoreDem=0;
		       //   int enr=0;
		          if(exist==1 && dejaAmi==1 && pasEncoreDem==1) serveur.enregistrerDemande(email, demande);
		          else 
		          out.write("D"+exist+dejaAmi+pasEncoreDem);out.flush();
		          exist=2; dejaAmi=2; pasEncoreDem=2;
		    	  break;
		        }//fin else
		    }//fin while
	}//fin demande()
      		
	/** Methode qui verifie s'il y a des demandes des la connexion **/
    public void verifDemande() throws IOException
    {
  		String email="";
    	boolean dem=false;
    	in.read(charCur, 0, 1);
    	while(charCur[0]!=9) //pour eviter le break
	    {
	      	// on regarde si on arrive à la fin d'une chaine ...
	        if (charCur[0] != '\u0000' && charCur[0] != '\n' && charCur[0] != '\r')
	        {
	        	if(charCur[0]!=';' && dem==false)
	                email += charCur[0]; // ... si non, on concatène le caractère dans le message
	        	else{
	        			dem=true;			        			
	        	}
		        in.read(charCur, 0, 1);		        
	        }
	        else if(!email.equalsIgnoreCase("")) // juste une vérification de principe
	        {
	          existe2=serveur.verifierDemande(email);
	          out.write("V"+existe2);
	          out.flush();
	          charCur[0]= 9;//pour eviter le break
	        }
	    }//fin while  */
    }//fin verifdemande()
    
    /** Methode envoieMess **/
    public void envoieMess() throws IOException
    {
	   	 message="";
		 var="";
		 while(in.read(charCur,0,1)!=-1){
			 if (charCur[0] != '\u0000'){
				 if (charCur[0] != ';' && message.equals(""))
					 var=var+charCur[0];
				 else{
					 if(charCur[0]!=';')
						 message=message+charCur[0];
					 else{
						 in.read(charCur,0,1);
						 message=message+charCur[0];
					 }
				 }
			 }
			 else{
				 serveur.envoieClient(message, var, email);
				 break;
			 }
		 }//fin while
    }//fin envoieMess()
    
    /** Methode quiafficheles demandes **/
    public void afficheDemande() throws IOException
    {
  		String email="";
    	boolean dem=false;
    	in.read(charCur, 0, 1);
    	while(charCur[0]!=-1) {
	      	// on regarde si on arrive à la fin d'une chaine ...
	        if (charCur[0] != '\u0000' && charCur[0] != '\n' && charCur[0] != '\r')
	        {
	        	if(charCur[0]!=';' && dem==false)
	                email += charCur[0]; // ... si non, on concatène le caractère dans le message
	        	else{
	        			dem=true;			        			
	        	}
		        in.read(charCur, 0, 1);
	        }
	        else if(!email.equalsIgnoreCase("")) // juste une vérification de principe
	        {
	          demandeur=serveur.afficherDemande(email);
		      out.write("R"+demandeur);
		      out.flush();//renvoie a Communication Client		      
	          break;
	        }
	    }//fin while  */
    }//fin afficheDemande()
    
    /** Methode appelee lorsque la demande est acceptee **/
    public void demandeAcceptee() throws IOException
    {
  		email=""; String demandeur="";
    	boolean dem=false;
    	in.read(charCur, 0, 1);
    	while(charCur[0]!=-1 ) {
	      	// on regarde si on arrive à la fin d'une chaine ...
	        if (charCur[0] != '\u0000' && charCur[0] != '\n' && charCur[0] != '\r')
	        {
	        	if(charCur[0]!=';' && dem==false)
	                email += charCur[0]; // ... si non, on concatène le caractère dans le message
	        	else{
	        			dem=true;
	        			if(charCur[0]!=';')
	        				demandeur +=charCur[0];
	        	}
		        in.read(charCur, 0, 1);
	        }
	        else if(!email.equalsIgnoreCase("")&& !demandeur.equalsIgnoreCase("")) // juste une vérification de principe
	        {
		      int ok = serveur.accepterDemande(demandeur, email);
	          out.write("O"+ok); out.flush();			      
	          break;
	        }
	      }//fin while  
    }//fin demande acceptee()
    
    /** Methode qui supprime la demande **/
    public void supprimeDemande() throws IOException
    {
    	email=""; String demandeur="";
    	boolean dem=false;
    	in.read(charCur, 0, 1);
    	while(charCur[0]!=-1 ) {
	      	// on regarde si on arrive à la fin d'une chaine ...
	        if (charCur[0] != '\u0000' && charCur[0] != '\n' && charCur[0] != '\r')
	        {
	        	if(charCur[0]!=';' && dem==false)
	                email += charCur[0]; // ... si non, on concatène le caractère dans le message
	        	else
	        	{
	        			dem=true;
	        			if(charCur[0]!=';')
	        				demandeur +=charCur[0];
	        	}
		        in.read(charCur, 0, 1);
	        }
	        else if(!email.equalsIgnoreCase("")&& !demandeur.equalsIgnoreCase("")) // juste une vérification de principe
	        {
		      int ok = serveur.supprimerDemande(demandeur, email);
	          out.write("S"+ok);
	          out.flush();			      
	          break;
	        }

	      }//fin while  
    }//fin supprime demande
    
    public void deconnexionClient() throws IOException, SQLException{
    	email="";
    	while(in.read(charCur, 0, 1)!= -1){
    		if(charCur[0]!='\u0000'){
    			email=email+charCur[0];
    		}
    		else{
    			serveur.delClient(email);
        		serveur.ActualiseListeAmis(email, false);
    			break;
    		}
    	}
    	
    }
    
    public void actualisationStatut() throws IOException, SQLException{
    	email="";
    	String statut="";
    	while(in.read(charCur, 0, 1)!= -1){
    		if(charCur[0]!='\u0000'){
    			if(charCur[0]!=';'&& statut==""){
    				email=email+charCur[0];
    			}
    			else
    				if(statut==""){
    					in.read(charCur, 0, 1);
    					statut=statut+charCur[0];
    				}  
    				else
    					statut=statut+charCur[0];
    		}
    		else{
    			client.setStatut(statut);
    			serveur.actualiseStatuts(email,statut);
    			break;
    		}
    	}
    }
    
    public void actualisationPseudo() throws IOException, SQLException{
    	email="";
    	String pseudo="";
    	while(in.read(charCur, 0, 1)!= -1){
    		if(charCur[0]!='\u0000'){
    			if(charCur[0]!=';'&& pseudo==""){
    				email=email+charCur[0];
    			}
    			else
    				if(pseudo==""){
    					in.read(charCur, 0, 1);
    					pseudo=pseudo+charCur[0];
    				}  
    				else
    					pseudo=pseudo+charCur[0];
    		}
    		else{
    			client.setPseudo(pseudo);
    			serveur.actualisePseudos(email,pseudo);
    			break;
    		}
    	}
    }
    
    public void envoieMessHL() throws IOException{
    	String s[];
    	String var="";
    	while(in.read(charCur, 0, 1)!= -1){
    		if(charCur[0]!='\u0000'){
    			var=var+charCur[0];
    		}
    		else{
    			s=var.split(";");
    			serveur.enregistreMessage(s[0], s[1],s[2]);
    			break;
    		}
    	}   	
    }
    
    public void supprimeMess() throws IOException{
    	String var="";
    	while(in.read(charCur, 0, 1)!= -1){
    		if(charCur[0]!='\u0000'){
    			var=var+charCur[0];
    		}
    		else{
    			serveur.supprimeMess(var);
    			break;
    		}
    	}   	
    	
    }

}//fin Classe ThreadClient

